package com.core.image.core.impl.async;

import com.core.image.core.*;
import com.core.image.core.box.StringRecevicePacket;
import com.core.image.utils.CloseUtils;
import com.sun.org.apache.regexp.internal.RE;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * describe:
 *
 * @author 库琦
 * @date 2020/01/24
 */
public class AsncReceiveDispatcher implements ReceiveDispacher,
        IoArgs.IoArgsEventProcessor,
        AsyncPacketWriter.PacketProvider{
    private AtomicBoolean isClosed = new AtomicBoolean(false);
    private final Receiver receiver;
    private IoArgs ioArgs = new IoArgs();
    private AsyncPacketWriter writer = new AsyncPacketWriter(this);
    private ReceivePacket<?,?> packetTemp;
    private final ReceivePacketCalback callback;
    public AsncReceiveDispatcher(Receiver receiver, ReceivePacketCalback callback) {
        this.receiver = receiver;
        this.receiver.setReceiveListener(this);
        this.callback = callback;
    }
    @Override
    public void start() {
        registerReceive();
    }
    private void registerReceive(){
        try {
            receiver.postReceiveAsync();
        }catch (Exception e){
        closeAndNotify();
        }
    }
    private void closeAndNotify() {
        CloseUtils.close(this);
    }
    @Override
    public void stop() {

    }
    @Override
    public void close() throws IOException {
            if (isClosed.compareAndSet(false,true)){
                writer.close();
                ReceivePacket packet = this.packetTemp;
                if (packet != null){
                    packetTemp = null;
                    CloseUtils.close(packet);
                }
            }
    }



    @Override
    public IoArgs provideIoArgs() {
        IoArgs ioArgs = writer.takeIoArgs();
        ioArgs.startWriting();
        return ioArgs;
    }

    @Override
    public void onConsumeFailed(IoArgs ioArgs, Exception e) {
            e.printStackTrace();

    }

    @Override
    public void onConsumeComplete(IoArgs ioArgs) {
        if (isClosed.get()){
            return;
        }
            ioArgs.finishWriting();
            do {
                writer.consumeIoArgs(ioArgs);
            }while (ioArgs.remained()&&!isClosed.get());
                 registerReceive();


    }

    @Override
    public ReceivePacket takePacket(byte type, long length, byte[] headerInfo) {
        return callback.onArriveNewPacket(type,length,headerInfo);
    }

    @Override
    public void completedPacket(ReceivePacket packet, boolean isSuccessed) {
            CloseUtils.close(packet);
            callback.onReceivePacketCompleted(packet);

    }

    @Override
    public void onReceivedHeartbeat() {
        callback.onReceivedHeartbeat();
    }
}
